#include <stdio.h>
#include <Python.h>
#include "c3ga.h"

static PyObject *
ga_vp(PyObject *self, PyObject *args)
{
    char res[1024];
    const char *mv1, *mv2;
    
    if (!PyArg_ParseTuple(args, "ss", &mv1, &mv2)) 
        return NULL;

    mv x, y, z;

    parse_mv(&x, mv1);
    parse_mv(&y, mv2);
    applyVersor_mv_mv(&z, &x, &y);
    toString_mv(&z, res, 1024, "%f");

    return Py_BuildValue("s", res);
}

static PyObject *
ga_e1(PyObject *self, PyObject *args)
{
	float res;
	const char *mv1;

	if (!PyArg_ParseTuple(args, "s", &mv1))
		return NULL;

	mv x;

	parse_mv(&x, mv1);
	res = mv_e1(&x);
	
	return Py_BuildValue("f", res);
}

static PyObject *
ga_e2(PyObject *self, PyObject *args)
{
	float res;
	const char *mv1;

	if (!PyArg_ParseTuple(args, "s", &mv1))
		return NULL;

	mv x;

	parse_mv(&x, mv1);
	res = mv_e2(&x);
	
	return Py_BuildValue("f", res);
}

static PyObject *
ga_e3(PyObject *self, PyObject *args)
{
	float res;
	const char *mv1;

	if (!PyArg_ParseTuple(args, "s", &mv1))
		return NULL;

	mv x;

	parse_mv(&x, mv1);
	res = mv_e3(&x);
	
	return Py_BuildValue("f", res);
}

static PyObject *
ga_ni(PyObject *self, PyObject *args)
{
	float res;
	const char *mv1;

	if (!PyArg_ParseTuple(args, "s", &mv1))
		return NULL;

	mv x;

	parse_mv(&x, mv1);
	res = mv_ni(&x);
	
	return Py_BuildValue("f", res);
}

static PyObject *
ga_e1_e2(PyObject *self, PyObject *args)
{
	float res;
	const char *mv1;

	if (!PyArg_ParseTuple(args, "s", &mv1))
		return NULL;

	mv x;

	parse_mv(&x, mv1);
	res = mv_e1_e2(&x);
	
	return Py_BuildValue("f", res);
}

static PyObject *
ga_e2_e3(PyObject *self, PyObject *args)
{
	float res;
	const char *mv1;

	if (!PyArg_ParseTuple(args, "s", &mv1))
		return NULL;

	mv x;

	parse_mv(&x, mv1);
	res = mv_e2_e3(&x);
	
	return Py_BuildValue("f", res);
}

static PyObject *
ga_e2_ni(PyObject *self, PyObject *args)
{
	float res;
	const char *mv1;

	if (!PyArg_ParseTuple(args, "s", &mv1))
		return NULL;

	mv x;

	parse_mv(&x, mv1);
	res = mv_e2_ni(&x);
	
	return Py_BuildValue("f", res);
}
	
static PyObject *
ga_div(PyObject *self, PyObject *args)
{
        char res[1024];
        float scalar;
        const char *mv1;

        if (!PyArg_ParseTuple(args, "sf", &mv1, &scalar))
                return NULL;

        mv x, y;

        parse_mv(&x, mv1);
        div_mv_float(&y, &x, scalar);
        toString_mv(&y, res, 1024, "%f");

        return Py_BuildValue("s", res);
}

static PyObject *
ga_unit(PyObject *self, PyObject *args)
{
	char res[1024];
	const char *mv1;

	if (!PyArg_ParseTuple(args, "s", &mv1))
		return NULL;
	
	mv x, y;
	
	parse_mv(&x, mv1);
	unit_mv(&y, &x);
	toString_mv(&y, res, 1024, "%f");

	return Py_BuildValue("s", res);
}

static PyObject *
ga_op(PyObject *self, PyObject *args)
{

    char res[1024];
    const char *mv1, *mv2;
    
    if (!PyArg_ParseTuple(args, "ss", &mv1, &mv2)) 
        return NULL;

    mv x, y, z;

    parse_mv(&x, mv1);
    parse_mv(&y, mv2);
    op_mv_mv(&z, &x, &y);
    toString_mv(&z, res, 1024, "%f");

    return Py_BuildValue("s", res);
}

static PyObject *
ga_lc(PyObject *self, PyObject *args)
{

    char res[1024];
    const char *mv1, *mv2;
    
    if (!PyArg_ParseTuple(args, "ss", &mv1, &mv2)) 
        return NULL;

    mv x, y, z;

    parse_mv(&x, mv1);
    parse_mv(&y, mv2);
    lc_mv_mv(&z, &x, &y);
    toString_mv(&z, res, 1024, "%f");

    return Py_BuildValue("s", res);
}

static PyObject *
ga_add(PyObject *self, PyObject *args)
{

    char res[1024];
    const char *mv1, *mv2;
    
    if (!PyArg_ParseTuple(args, "ss", &mv1, &mv2)) 
        return NULL;

    mv x, y, z;

    parse_mv(&x, mv1);
    parse_mv(&y, mv2);
    add_mv_mv(&z, &x, &y);
    toString_mv(&z, res, 1024, "%f");

    return Py_BuildValue("s", res);
}

static PyObject *
ga_gp(PyObject *self, PyObject *args)
{

    char res[1024];
    const char *mv1, *mv2;
    
    if (!PyArg_ParseTuple(args, "ss", &mv1, &mv2)) 
        return NULL;

    mv x, y, z;

    parse_mv(&x, mv1);
    parse_mv(&y, mv2);
    gp_mv_mv(&z, &x, &y);
    toString_mv(&z, res, 1024, "%f");

    return Py_BuildValue("s", res);
}

static PyObject *
ga_dual(PyObject *self, PyObject *args)
{

    char res[1024];
    const char *mv1;
    
    if (!PyArg_ParseTuple(args, "s", &mv1))
        return NULL;

    mv x, y;

    parse_mv(&x, mv1);
    dual_mv(&y, &x);
    toString_mv(&y, res, 1024, "%f");

    return Py_BuildValue("s", res);
}

static PyMethodDef GaMethods[] = {
    {"op", ga_op, METH_VARARGS, "Perform the outer product."},
    {"lc", ga_lc, METH_VARARGS, "Perform the left contraction/inner product."},
    {"gp", ga_gp, METH_VARARGS, "Perform the geometric product."},
    {"div", ga_div, METH_VARARGS, "Divides a multivector by a scalar."},
    {"vp", ga_vp, METH_VARARGS, "Apply the versor product."},
    {"add", ga_add, METH_VARARGS, "Adds together two multivectors."},
    {"dual", ga_dual, METH_VARARGS, "Returns the dual of the given multivector."},
	{"unit", ga_unit, METH_VARARGS, "Returns unit of multivector using default metric"},
    {"gete1", ga_e1, METH_VARARGS, "Return e1 coordinate of multivector"},
    {"gete2", ga_e2, METH_VARARGS, "Return e2 coordinate of multivector"},
    {"gete3", ga_e3, METH_VARARGS, "Return e3 coordinate of multivector"},
    {"getni", ga_ni, METH_VARARGS, "Return ni coordinate of multivector"},
    {"gete1e2", ga_e1_e2, METH_VARARGS, "Return ni coordinate of multivector"},
    {"gete2e3", ga_e2_e3, METH_VARARGS, "Return ni coordinate of multivector"},
    {"gete2ni", ga_e2_ni, METH_VARARGS, "Return ni coordinate of multivector"},
    {NULL, NULL, 0, NULL}
};

static char ga_doc[] = "A module implementing standard GA methods.\n";
    
PyMODINIT_FUNC initga(void)
{
	PyObject *module = Py_InitModule3("ga", 
                                      GaMethods, ga_doc);
	PyModule_AddStringConstant(module, 
                              "__version__", 
                              "0.1a");
	PyModule_AddStringConstant(module,
                               "__author__",
                               "Moos Hueting");
}
